/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use std::sync::Arc;

use anyhow::Result;
use async_trait::*;
use once_cell::sync::OnceCell;

pub use base::*;
pub use build::*;
pub use impl_nats::*;

use crate::{configs::*, discover::*, errors::NatsError, logger::*, treaty::*};
use crate::{error, fatal, info};

mod base;
mod build;
mod impl_nats;

static DEF_RPC: OnceCell<ServerRpc> = OnceCell::new();

pub async fn init_rpc(cfg: RpcConf) {
    if &cfg.use_type != "nats" {
        fatal!("not support rpc type: {}", &cfg.use_type);
        return;
    }
    match new_rpc_server(get_rpc_conf(), None).await {
        Ok(rpc) => {
            if let Err(_) = DEF_RPC.set(rpc) {
                fatal!("init_rpc err");
            }
        }
        Err(err) => {
            fatal!("init_rpc err:{}", err);
        }
    }
}

pub fn close_rpc() {
    let rpc = global_rpc();
    if let Err(err) = rpc.close() {
        error!("close rpc err:{}", err);
    }
}

//global function
pub fn global_rpc() -> &'static ServerRpc {
    DEF_RPC.get().expect("rpc is not initialized")
}

pub fn publish(s: ReqBuilder) -> Result<(), NatsError> {
    let rpc = global_rpc();
    rpc.publish(s)
}

pub fn publish_broadcast(s: ReqBuilder) -> Result<(), NatsError> {
    let rpc = global_rpc();
    rpc.publish_broadcast(s)
}

pub fn queue_publish(s: ReqBuilder) -> Result<(), NatsError> {
    let rpc = global_rpc();
    rpc.queue_publish(s)
}

pub fn request(s: ReqBuilder) -> Result<Vec<u8>, NatsError> {
    let rpc = global_rpc();
    rpc.request(s)
}

pub fn queue_request(s: ReqBuilder) -> Result<Vec<u8>, NatsError> {
    let rpc = global_rpc();
    rpc.queue_request(s)
}

pub fn find_server(
    server_type: &str,
    arg: String,
    options: Option<Vec<FilterOption>>,
) -> Option<Server> {
    let rpc = global_rpc();
    rpc.find_server(server_type, arg, options)
}

pub fn remove_find_cache(arg: String) {
    let rpc = global_rpc();
    rpc.remove_find_cache(arg)
}

pub type CallbackFunc = Arc<dyn Fn(&Vec<u8>) -> Option<Vec<u8>> + Send + Sync>;

pub fn default_callback(req: &Vec<u8>) -> Option<Vec<u8>> {
    info!("default callback:{:?}", req);
    None
}

pub type ServerRpc = Arc<dyn IServerRpc + Sync + Send>;

pub trait IServerRpc {
    fn subscribe(&self, s: RssBuilder) -> Result<(), NatsError>;
    fn subscribe_broadcast(&self, s: RssBuilder) -> Result<(), NatsError>;
    fn queue_subscribe(&self, s: RssBuilder) -> Result<(), NatsError>;
    fn publish(&self, s: ReqBuilder) -> Result<(), NatsError>;
    fn publish_broadcast(&self, s: ReqBuilder) -> Result<(), NatsError>;
    fn queue_publish(&self, s: ReqBuilder) -> Result<(), NatsError>;
    fn request(&self, s: ReqBuilder) -> Result<Vec<u8>, NatsError>;
    fn queue_request(&self, s: ReqBuilder) -> Result<Vec<u8>, NatsError>;
    fn get_server(&self) -> Option<Server>;
    fn find_server(
        &self,
        server_type: &str,
        arg: String,
        options: Option<Vec<FilterOption>>,
    ) -> Option<Server>;
    fn remove_find_cache(&self, arg: String);
    fn close(&self) -> Result<(), NatsError>;
}
